#include "Player.h"
#include "Game.h"
#include "ObjectDatabase.h"
#include "Renderer.h"
#include "StringLib.h"
#include "GameState.h"
#include "Potion.h"
#include "Scroll.h"
#include "LockedObstacle.h"
#include "Food.h"
#include "Tile.h"
#include "Equipment.h"
#include "Level.h"
#include "Door.h"
#include "ItemContainer.h"
#include "MeleeWeapon.h"
#include "RangedWeapon.h"
#include "Npc.h"
#include "Resource.h"
#include "Keyboard.h"
#include "Tool.h"

Player::Player(PlayerType type) : Character(GT_CH_PLAYER) {
	m_types[TH_PLAYER_TYPE] = type;
	const PlayerInfo& info = g_objectDatabase->getPlayerInfo(type);
	for(int i = 0; i < NUM_STATS; i++)
		m_stats[i] = info.stats[i];
	m_maxHealth = m_currentHealth = info.health;
	m_satiation = 2990;
	m_turnCounter = -1;
	m_level = 1;
	m_gender = GT_MALE;
	m_skills[SKI_EXPLOIT] = 1.0f;
}

Player::Player(std::ifstream& file) : Character(GT_CH_PLAYER, file) {
	int* tokens = Util::intSplit(file);
	m_types[TH_PLAYER_TYPE] = tokens[0];
	m_satiation = tokens[1];
	for(int i = 0; i < tokens[2]; i++)
		m_talents.insert(Talent(tokens[2+i]));
	delete[] tokens;
	g_player = this;
}

Player::~Player() {
}

void Player::save(std::ofstream& file) const {
	file << getType(TH_GENERIC_TYPE) << "\n";
	Character::save(file);
	file << getType(TH_PLAYER_TYPE) << " " << m_satiation << " " << m_talents.size();
	for(std::set<Talent>::const_iterator iter = m_talents.begin(); iter != m_talents.end(); iter++)
		file << " " << (*iter);
	file << "\n";
}

void Player::render(float x, float y) {
	g_renderer->render(*this, x, y);
}

void Player::logDetails(TextLog& log) const {
	Character::logDetails(log);
	log.addBlankLine();
	if(m_gender == GT_NONE)
		log.addLine(g_stringLib->getTextString(ST_PLAYER_GENDER_NONE));
	else
		log.addLine(g_stringLib->getTextString(ST_PLAYER_GENDER, g_stringLib->getMiscString(MST_GENDER, m_gender).c_str()));
	log.addLine(g_stringLib->getTextString(ST_PLAYER_HEALTH_STATUS, g_stringLib->getMiscString(MST_HEALTH, getHealthStatus()).c_str()));
}

std::string Player::getName() const {
	return GameObject::getName();
}

bool Player::move(int x, int y) {
	int currX = int(m_tile->getX()), currY = int(m_tile->getY());
	bool moved = Character::move(x, y);
	
	if(!moved) {
		int newX = currX+x, newY = currY+y;
		if(m_tile->getLevel()->getTile(newX, newY)->getObstacle() != NULL && m_tile->getLevel()->getTile(newX, newY)->getObstacle()->getType(TH_GENERIC_TYPE) == GT_OB_RESOURCE) {
			if(m_equipment->get(EL_LEFT_HAND) != NULL && m_equipment->get(EL_LEFT_HAND)->getType(TH_GENERIC_TYPE) == GT_IT_TOOL
					&& ((Resource*)m_tile->getLevel()->getTile(newX, newY)->getObstacle())->isRightTool(*((Tool*)m_equipment->get(EL_LEFT_HAND)))) {
				gatherResource(((Resource*)m_tile->getLevel()->getTile(newX, newY)->getObstacle()), ((Tool*)m_equipment->get(EL_LEFT_HAND)));
				moved = true;
			} else if(m_equipment->get(EL_RIGHT_HAND) != NULL && m_equipment->get(EL_RIGHT_HAND)->getType(TH_GENERIC_TYPE) == GT_IT_TOOL
					&& ((Resource*)m_tile->getLevel()->getTile(newX, newY)->getObstacle())->isRightTool(*((Tool*)m_equipment->get(EL_RIGHT_HAND)))) {
				gatherResource(((Resource*)m_tile->getLevel()->getTile(newX, newY)->getObstacle()), ((Tool*)m_equipment->get(EL_RIGHT_HAND)));
				moved = true;
			}
		}
	} else {
		int newX = int(m_tile->getX()), newY = int(m_tile->getY());
		if(currX != newX || currY != newY)
			m_tile->getLevel()->getTile(newX, newY)->logDetails(*g_textLog);
	}
	return moved;
}

void Player::moveToNewTile(int x, int y) {
	Character::moveToNewTile(x, y);
	calculateFOV();
}

void Player::calculateFOV() {
	for(std::set<Tile*>::iterator iter = m_visibleTiles.begin(); iter != m_visibleTiles.end(); iter++) {
		(*iter)->setVisible(false);
	}
	m_visibleTiles.clear();

	m_tile->getLevel()->calculateFOV(int(m_tile->getX()), int(m_tile->getY()), 2+m_stats[PER]/3, m_visibleTiles);

	for(std::set<Tile*>::iterator iter = m_visibleTiles.begin(); iter != m_visibleTiles.end(); iter++)
		(*iter)->setVisible(true);
}

bool Player::equip(EquipmentLocation location, Item* item, bool takeTurn) {
	if(Character::equip(location, item, takeTurn)) {
		((EquippableItem*)item)->identify();
		if(item->getStatus() == CURSED)
			item->statusIdentify();
		g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_EQUIP, item->getColoredName().c_str()));
		return true;
	} else {
		g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_EQUIP_FAIL, item->getColoredName().c_str()));
		return false;
	}
}

bool Player::unequip(EquipmentLocation location) {
	Item* item = m_equipment->get(location);
	if(Character::unequip(location)) {
		g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_UNEQUIP, item->getColoredName().c_str()));
		return true;
	} else {
		g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_UNEQUIP_FAIL, item->getColoredName().c_str()));
		return false;
	}
}

Item* Player::drop(int index) {
	if(size_t(index) >= m_inventory->size()) return NULL;
	std::list<Item*>::iterator iter = m_inventory->begin();
	std::advance(iter, index);
	return drop(*iter);
}

Item* Player::drop(Item* item) {
	EquipmentLocation location = m_equipment->whereEquipped(item);
	if(location != NUM_EQUIPMENT_LOCATIONS) {
		if(!unequip(location))
			return NULL;
	}
	forceRemoveItemFromInventory(item);
	m_tile->addItem(item);
	item->setParentList(m_tile->getItems());
	modifyTurnCounter(DEFAULT_TURN_LENGTH/2);
	g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_DROP, item->getColoredName().c_str()));
	return item;
}

bool Player::pickUp(Item* item) {
	bool pickedUp = Character::pickUp(item);
	if(pickedUp)
		g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_PICK_UP, item->getColoredName().c_str()));
	else
		g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_PICK_UP_FAIL, item->getColoredName().c_str()));
	return pickedUp;
}

bool Player::dealDamage(int damage) {
	bool dead = Character::dealDamage(damage);
	if(getHealthStatus() != HS_NOT_WOUNDED)
		g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_HEALTH_STATUS, g_stringLib->getMiscString(MST_HEALTH, getHealthStatus()).c_str()));
	if(m_currentHealth <= 0) {
		g_gameMode.push(GM_DEAD);
		deleteOldGame();
	}
	return dead;
}

void Player::giveExperience(int exp) {
	Character::giveExperience(exp);
	if(m_level == MAX_LEVEL)
		return;
	while(m_experience >= levelThresholds[m_level+1]) {
		m_level++;
		g_gameMode.push(GM_SELECT_SKILL);
		if(m_level % 10 == 0) {
			g_gameMode.push(GM_SELECT_NEW_SKILL);
		}
		if((m_level-2) % 3 == 0) {
			g_gameMode.push(GM_SELECT_TALENT);
			g_keyboard->initTalentList(this);
		}
		g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_LEVEL_UP, Util::intToString(m_level).c_str()));
		m_maxHealth = x_plus(m_maxHealth, 10);
		m_currentHealth = m_maxHealth;
		int totalStats = 0;
		for(int i = 0; i < NUM_STATS; i++)
			totalStats += m_stats[i];
		for(int i = 0; i < NUM_STATS; i++)
			if(x_in_y(m_stats[i], totalStats)) changeStat(Stat(i), 1);
	}
}

bool Player::poison(int damage) {
	g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_POISON_DAMAGE));
	return Character::poison(damage);
}

void Player::changeStat(Stat stat, int mod) {
	Character::changeStat(stat, mod);
	switch(stat) {
	case STR:
		if(mod < 0)
			g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_LOSE_STR));
		else if(mod > 0)
			g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_GAIN_STR));
		break;
	case COM:
		if(mod < 0)
			g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_LOSE_COM));
		else if(mod > 0)
			g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_GAIN_COM));
		break;
	case NIM:
		if(mod < 0)
			g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_LOSE_NIM));
		else if(mod > 0)
			g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_GAIN_NIM));
		break;
	case LOR:
		if(mod < 0)
			g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_LOSE_LOR));
		else if(mod > 0)
			g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_GAIN_LOR));
		break;
	case PER:
		if(mod < 0)
			g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_LOSE_PER));
		else if(mod > 0)
			g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_GAIN_PER));
		break;
	}
}

void Player::modifyTurnCounter(int mod) {
	Character::modifyTurnCounter(mod);
	if(mod == -DEFAULT_TURN_LENGTH) {
		if((m_equipment->isEquipped(EL_LEFT_HAND) && m_equipment->get(EL_LEFT_HAND)->getType(TH_GENERIC_TYPE) == GT_IT_MELEE_WEAPON && ((MeleeWeapon*)m_equipment->get(EL_LEFT_HAND))->getSuffix() == MWS_OF_GLUTTONY)
				|| (m_equipment->isEquipped(EL_RIGHT_HAND) && m_equipment->get(EL_RIGHT_HAND)->getType(TH_GENERIC_TYPE) == GT_IT_MELEE_WEAPON && ((MeleeWeapon*)m_equipment->get(EL_RIGHT_HAND))->getSuffix() == MWS_OF_GLUTTONY))
			m_satiation -= 10;
		else
			m_satiation -= 5;
		if(m_talents.count(TAL_SATIATION_1))
			m_satiation += 1;
		if(m_talents.count(TAL_SATIATION_2))
			m_satiation += 1;
		if(m_satiation <= 0) {
			g_gameMode.push(GM_DEAD);
			deleteOldGame();
			g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_STARVED));
		}
	} else if(mod > 0) {
		g_gameState->markPlayerTookTurn();
	}
}

SatiationStatus Player::getSatiationStatus() const {
	if(m_satiation > 5000)
		return SS_BLOATED;
	else if(m_satiation > 4000)
		return SS_VERY_FULL;
	else if(m_satiation > 3000)
		return SS_FULL;
	else if(m_satiation > 1500)
		return SS_NORMAL;
	else if(m_satiation > 1000)
		return SS_HUNGRY;
	else if(m_satiation > 500)
		return SS_VERY_HUNGRY;
	else
		return SS_STARVING;
}

bool Player::quaff(Potion* potion) {
	g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_QUAFF, potion->getColoredName().c_str()));
	bool quaffed = Character::quaff(potion);
	if(!quaffed) {
		switch(potion->getType(TH_POTION_TYPE)) {
		case PT_GAIN_ATTR:
			if(potion->getStatus() == BLESSED) {
				for(int i = STR; i < NUM_STATS; i++) {
					changeStat(Stat(i), 1);
				}
			} else {
				Stat location = Stat(rand(NUM_STATS));
				if(potion->getStatus() == CURSED)
					changeStat(location, -1);
				else
					changeStat(location, 1);
			}
			potion->identify();
			potion->statusIdentify();
			quaffed = true;
			break;
		case PT_WATER:
			switch(potion->getStatus()) {
			case CURSED:
				m_satiation += 10;
				g_textLog->addLine(g_stringLib->getTextString(ST_QUAFF_WATER_CURSED));
				break;
			case UNCURSED:
				m_satiation += 50;
				g_textLog->addLine(g_stringLib->getTextString(ST_QUAFF_WATER_UNCURSED));
				break;
			case BLESSED:
				m_satiation += 100;
				g_textLog->addLine(g_stringLib->getTextString(ST_QUAFF_WATER_BLESSED));
				break;
			}
			potion->identify();
			potion->statusIdentify();
			quaffed = true;
			break;
		}	
		if(quaffed) {
			modifyTurnCounter(DEFAULT_TURN_LENGTH / 3);
			potion->reduceStackCount(1, true, m_inventory);
		}
	} else {
		switch(potion->getType(TH_POTION_TYPE)) {
		case PT_HEALING:
		case PT_POISON:
		case PT_INVIS:
			potion->identify();
		}
	}
	return quaffed;
}

void Player::heal(int amount) {
	Character::heal(amount);
	g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_HEAL));
}

void Player::logCombat(Character* enemy, bool nothing, bool hit, bool blocked, int damage, bool crit, bool flame, bool envy, bool lust) {
	if(nothing) {
		g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_MELEE_NOTHING, getColoredName().c_str()));
	} else if(!hit) {
		g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_MELEE_MISS, enemy->getColoredName().c_str()));
	} else if(blocked) {
		g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_MELEE_BLOCKED, enemy->getColoredName().c_str()));
	} else {
		if(crit)
			g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_MELEE_CRIT));
		if(flame)
			g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_MELEE_FLAME, enemy->getColoredName().c_str()));
		if(envy)
			g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_MELEE_ENVY, enemy->getColoredName().c_str()));
		else if(lust)
			g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_MELEE_LUST, enemy->getColoredName().c_str()));

		g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_MELEE_HIT, enemy->getColoredName().c_str(), Util::intToString(damage).c_str()));
	}
}

bool Player::addStatusEffect(StatusEffect effect, int power) {
	if(Character::addStatusEffect(effect, power)) {
		g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_STATUS_EFFECT_COMPOUND, g_stringLib->getMiscString(MST_STATUS_EFFECT, effect).c_str()));
		return true;
	} else {
		g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_STATUS_EFFECT_GAIN, g_stringLib->getMiscString(MST_STATUS_EFFECT, effect).c_str()));
		return false;
	}
}

bool Player::removeStatusEffect(StatusEffect effect) {
	if(Character::removeStatusEffect(effect)) {
		g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_STATUS_EFFECT_LOSE, g_stringLib->getMiscString(MST_STATUS_EFFECT, effect).c_str()));
		return true;
	}
	return false;
}

void Player::doKick(int x, int y) {
	int newX = int(m_tile->getX())+x;
	int newY = int(m_tile->getY())+y;
	Character* c = g_currentLevel->getTile(newX, newY)->getCharacter();
	Obstacle* o = g_currentLevel->getTile(newX, newY)->getObstacle();
	std::list<Item*>* items = g_currentLevel->getTile(newX, newY)->getItems();
	if(c != NULL && (x != 0 || y != 0)) {
		kick(c);
	} else if(o != NULL && (o->getType(TH_GENERIC_TYPE) == GT_OB_DOOR || o->getType(TH_GENERIC_TYPE) == GT_OB_ITEMCONTAINER || o->getType(TH_GENERIC_TYPE) == GT_OB_RESOURCE || o->getType(TH_GENERIC_TYPE) == GT_OB_WALL)) {
		kick(o);
	} else if(items->size() > 0) {
		kick(*(items->begin()), x, y);
	} else {
		g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_KICK_NOTHING));
		modifyTurnCounter(DEFAULT_TURN_LENGTH);
	}
}

void Player::kick(GameObject* o, int x, int y) {
	int type = o->getType(TH_GENERIC_TYPE);
	if(type == GT_CH_PLAYER || type == GT_CH_NPC) {
		callMeleeAttack((Character*)o, MT_KICK);
	} else if(type == GT_OB_DOOR || type == GT_OB_ITEMCONTAINER || type == GT_OB_RESOURCE || type == GT_OB_WALL) {
		bool stubbed = false;
		switch(type) {
		case GT_OB_DOOR:
			if(((Door*)o)->isLocked() && ((Door*)o)->getLockType() != LT_NONE) {
				if(one_in(10)) {
					((Door*)o)->breakLock(true);
					g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_KICK_LOCK_FAIL));
				} else if(one_in(3)) {
					((Door*)o)->breakLock(false);
					g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_KICK_LOCK_SUCCEED, o->getColoredBasicName().c_str()));
				} else {
					stubbed = true;
				}
			} else if(!((Door*)o)->isOpen()) {
				stubbed = true;
			} else {
				g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_KICK_NOTHING));
				modifyTurnCounter(DEFAULT_TURN_LENGTH);
			}
			break;
		case GT_OB_WALL:
			stubbed = true;
			break;
		case GT_OB_ITEMCONTAINER: {
			ItemContainer* i = (ItemContainer*)o;
			if(i->getType(TH_ITEMCONTAINER_TYPE) == ICT_POTTERY) {
				g_textLog->addLine(g_stringLib->getTextString(ST_IC_SHATTER, i->getColoredName().c_str()));
				if(i->getItems()->size() == 0) {
					/*Npc* snake = new Npc(NT_SNAKE);
					g_gameState->addCharacter(snake);
					if(i->getTile()->getCharacter() == NULL) {
						i->getTile()->addCharacter(snake);
						g_textLog->addLine(g_stringLib->getTextString(ST_IC_HIDDEN_MONSTER, snake->getColoredName().c_str(), i->getColoredName().c_str()));
					} else {
						bool found = false;;
						for(int j = -1; j <= 1; j++) {
							for(int k = -1; k <= 1; k++) {
								if(!g_currentLevel->getTile(int(g_player->getTile()->getX())+x+j, int(g_player->getTile()->getY())+y+k)->isOccupied()) {
									found = true;
									g_currentLevel->getTile(int(g_player->getTile()->getX())+x+j, int(g_player->getTile()->getY())+y+k)->addCharacter(snake);
								}
							}
							if(found) break;
						}
						if(found)
							g_textLog->addLine(g_stringLib->getTextString(ST_IC_HIDDEN_MONSTER, snake->getColoredName().c_str(), i->getColoredName().c_str()));
					}*/
				} else {
					Item* item = *(i->getItems()->begin());
					i->removeItem(item);
					g_textLog->addLine(g_stringLib->getTextString(ST_IC_HIDDEN_ITEM, item->getColoredName().c_str(), i->getColoredName().c_str()));
					i->getTile()->addItem(item);
				}
				i->getTile()->removeObstacle();
				g_gameState->markForDeletion(i);
			} else if(i->getLockType() != LT_NONE) {
				if(one_in(10)) {
					i->breakLock(true);
					g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_KICK_LOCK_FAIL));
				} else if(one_in(3)) {
					i->breakLock(false);
					g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_KICK_LOCK_SUCCEED, i->getColoredName().c_str()));
				} else {
					stubbed = true;
				}
			} else {
				stubbed = true;
			}
			break;
		}
		case GT_OB_RESOURCE: {
			Resource* r = (Resource*)o;
			if(r->getType(TH_RESOURCE_FAMILY) == RF_PLANT) {
				g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_KICK_DESTROY_RESOURCE, r->getColoredName().c_str()));
				if(r->destroy(1)) {
					r->getTile()->removeObstacle();
					g_gameState->markForDeletion(r);
				}
			} else {
				stubbed = true;
			}
		}
		}
		if(stubbed) {
			dealDamage(1);
			g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_KICK_STUB));
		}
	} else {
		int playerX = int(g_player->getTile()->getX());
		int playerY = int(g_player->getTile()->getY());
		if(type == GT_IT_POTION) {
			((Potion*)o)->shatter(playerX+x, playerY+y);
		} else if(g_currentLevel->getTile(playerX+2*x, playerY+2*y)->getObstacle() == NULL
				|| (g_currentLevel->getTile(playerX+2*x, playerY+2*y)->getObstacle() != NULL && !g_currentLevel->getTile(playerX+2*x, playerY+2*y)->getObstacle()->isBlocking())) {
			g_currentLevel->getTile(playerX+x, playerY+y)->removeItem((Item*)o);
			g_currentLevel->getTile(playerX+2*x, playerY+2*y)->addItem((Item*)o);
			g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_KICK_ITEM_SLIDE_SUCCEED, o->getColoredName().c_str()));
		} else {
			g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_KICK_ITEM_SLIDE_FAIL, o->getColoredName().c_str()));
		}
	}
	modifyTurnCounter(DEFAULT_TURN_LENGTH);
}

void Player::logTrap(TrapType trap, bool hit, int damage) {
	switch(trap) {
	case TT_DAGGER:
		if(hit)
			g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_TRAP_DAGGER_HIT, Util::intToString(damage).c_str()));
		else
			g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_TRAP_DAGGER_MISS));
		break;
	}
}

void Player::eat(Food* food, bool inInventory) {
	if(getSatiationStatus() == SS_BLOATED) return;
	g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_EAT, food->getColoredName().c_str()));
	if(food->getSatiation() <= 0 || food->getStatus() == CURSED)
		g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_EAT_CURSED));
	else if(food->getStatus() == BLESSED)
		g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_EAT_BLESSED));
	m_satiation += food->getSatiation();
	food->eatEffects(this);
	if(inInventory)
		food->reduceStackCount(1, true, m_inventory);
	else
		m_tile->removeItem(food, true);
	modifyTurnCounter(DEFAULT_TURN_LENGTH);
}

bool Player::openDoor(Door* door) {
	unlockLock(door, 0);
	if(!door->isLocked()) {
		door->open();
		calculateFOV();
		modifyTurnCounter(DEFAULT_TURN_LENGTH/2);
		g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_OPEN_CLOSE_DOOR, std::string("open").c_str(), door->getColoredBasicName().c_str()));
		return true;
	}
	return false;
}

void Player::unlockLock(LockedObstacle* lock, int shouldLock) {
	if(shouldLock <= 1 && lock->isLocked() && hasKey(lock->getLockType()) && lock->getLockType() != LT_NONE) {
		lock->toggleLock();
		modifyTurnCounter(DEFAULT_TURN_LENGTH/2);
		g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_LOCK_UNLOCK, std::string("unlock").c_str(), lock->getColoredBasicName().c_str()));
	} else if(shouldLock >= 1 && !lock->isLocked() && hasKey(lock->getLockType())) {
		lock->toggleLock();
		modifyTurnCounter(DEFAULT_TURN_LENGTH/2);
		g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_LOCK_UNLOCK, std::string("lock").c_str(), lock->getColoredBasicName().c_str()));
	} else {
		if(lock->getLockType() == LT_NONE && lock->isLocked())
			g_textLog->addLine(g_stringLib->getTextString(ST_LOCK_DESTROYED, lock->getColoredBasicName().c_str()));
		else if(lock->getLockType() != LT_NONE && lock->isLocked())
			g_textLog->addLine(g_stringLib->getTextString(ST_INPUT_NO_KEY));
	}
}

void Player::readScroll(Scroll* scroll, Item* item) {
	g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_READ_SCROLL, scroll->getColoredName().c_str()));
	switch(scroll->getType(TH_SCROLL_TYPE)) {
	case ST_IDENTIFY:
		if(scroll->getStatus() == BLESSED) {
			for(std::list<Item*>::iterator iter = m_inventory->begin(); iter != m_inventory->end(); iter++) {
				(*iter)->identify();
				(*iter)->statusIdentify();
			}
			scroll->identify();
			g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_IDENTIFY_ALL));
		} else {
			item->identify();
			item->statusIdentify();
			g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_IDENTIFY, item->getColoredName().c_str()));
			scroll->identify();
		}
		break;
	case ST_UNCURSE:
		if(scroll->getStatus() == BLESSED) {
			for(std::list<Item*>::iterator iter = m_inventory->begin(); iter != m_inventory->end(); iter++) {
				(*iter)->setStatus(UNCURSED);
			}
			g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_UNCURSE_ALL));
		} else {
			if(item->getStatus() == CURSED) {
				item->setStatus(UNCURSED);
				g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_UNCURSE, item->getColoredName().c_str()));
				scroll->identify();
			} else {
				g_textLog->addLine(g_stringLib->getTextString(ST_NOTHING));
			}
		}
		break;
	}
	scroll->reduceStackCount(1, true, m_inventory);
	modifyTurnCounter(DEFAULT_TURN_LENGTH/2);
}

void Player::addTalent(Talent talent) {
	m_talents.insert(talent);
	g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_TALENT, g_stringLib->getMiscString(MST_TALENT, talent).c_str()));
	switch(talent) {
	case TAL_STR_1:
	case TAL_STR_2:
	case TAL_STR_3:
		changeStat(STR, 1);
		break;
	case TAL_COM_1:
	case TAL_COM_2:
	case TAL_COM_3:
		changeStat(COM, 1);
		break;
	case TAL_NIM_1:
	case TAL_NIM_2:
	case TAL_NIM_3:
		changeStat(NIM, 1);
		break;
	case TAL_LOR_1:
	case TAL_LOR_2:
	case TAL_LOR_3:
		changeStat(LOR, 1);
		break;
	case TAL_PER_1:
	case TAL_PER_2:
	case TAL_PER_3:
		changeStat(PER, 1);
		break;
	}
}

void Player::trainSkill(Skill skill, float amount) {
	int prev = getSkillLevel(skill);
	Character::trainSkill(skill, amount);
	int curr = getSkillLevel(skill);
	if(curr > prev)
		g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_SKILL_UP, g_stringLib->getMiscString(MST_SKILL, skill).c_str(), Util::intToString(curr).c_str()));
}

void Player::gatherResource(Resource* resource, Tool* tool) {
	std::list<Item*>* items = resource->gather(tool);
	if(items != NULL) {
		while(items->size() > 0) {
			Item* item = *(items->begin());
			items->remove(item);
			if(!addItemToInventory(item))
				m_tile->addItem(item);
		}
		delete items;

		if(resource->getNumResources() <= 0) {
			resource->getTile()->removeObstacle();
			g_gameState->markForDeletion(resource);
		}
	}

	modifyTurnCounter(int(DEFAULT_TURN_LENGTH * (float(tool->getSpeed())/100.0f)));
}

void Player::logReload(RangedWeapon* weapon, bool noAmmo) const {
	if(noAmmo)
		g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_RELOAD_NO_AMMO, weapon->getColoredName().c_str(), g_stringLib->getObjectString(TH_AMMO_TYPE, weapon->getAmmoType(), 2).c_str()));
	else
		g_textLog->addLine(g_stringLib->getTextString(ST_PLAYER_RELOAD, weapon->getColoredItemName().c_str()));
}
